/*
 * ...
 *
 */

#ifndef UNITRAF_GRAPHTRAITS_ITERATORADAPTOR_HPP
#define UNITRAF_GRAPHTRAITS_ITERATORADAPTOR_HPP

#include <iterator>

#include <graph\traits\Traits.hpp>

namespace unitraf {

namespace graph_traits {

// Making aliases
using std::iterator_traits;

template<
  class _Derived, 
  class _Base,
  class _ValTy =    typename iterator_traits<_Base>::value_type,
  class _PtrTy =    typename iterator_traits<_Base>::pointer,
  class _RefTy =    typename iterator_traits<_Base>::reference,
  class _IterCat =  typename iterator_traits<_Base>::iterator_category,
  class _DiffTy =   typename iterator_traits<_Base>::difference_type > 

    class IteratorAdaptor {

      typedef IteratorAdaptor _myt;

      // FRIENDS
      friend bool operator==(const _myt& lh, const _myt& rh) {
        return lh.iterator_ == rh.iterator_;
      };

      friend bool operator!=(const _myt& lh, const _myt& rh) {
        return lh.iterator_ != rh.iterator_;
      };

     public:
      /////////////////////////////////////////////////////////////////////////////
      // PUBLIC INTERFACE
    
      typedef _IterCat iterator_category;
      typedef _ValTy value_type;
      typedef _DiffTy difference_type;
      typedef _PtrTy pointer;
      typedef _RefTy reference;

      // CONSTRUCTORS AND INITIALIZERS

      IteratorAdaptor() {};

      IteratorAdaptor(const _Base& iterator) 
        : iterator_(iterator) {};

      
      // OPERATORS

      operator _Base() { return iterator_; };
      
      // REGULAR
      // METHODS

      _Derived& operator++() {
        ++iterator_;
        return this->_derived();
      };

      _Derived operator++(int) {
        _Derived old(this->_derived());
        ++iterator_;
        return old;
      };

      reference operator*() {
        return *iterator_;
      };

      pointer operator->() {
        return &(*iterator_);
      };

   
     private:
      /////////////////////////////////////////////////////////////////////////////
      // PRIVATE INTERFACE
    
      _Derived& _derived() {
        return *(static_cast<_Derived *>(this));
      };

    
      // REPRESENTATION
      // Iterator to base adaptor on to
      _Base iterator_;

    };

};  // namespace graph_traits

};  // namespace unitraf

#endif  // #ifndef UNITRAF_GRAPHTRAITS_ITERATORADAPTOR_HPP